package com.web.kdl.config.modbus;

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
import com.web.kdl.daoV2.matrix.MatrixDao;
import com.web.kdl.entity.matrix.Matrix;
import com.web.kdl.pojo.Vo.MatrixVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @Author： shulibin
 * @Date： 2025/11/4 9:48
 * @Describe：
 */
@Component
@Slf4j
public class Modbus4jFactory {

    // 统一管理 设备连接信息仓库
    private final Map<String, ModbusMaster> deviceConnections = new ConcurrentHashMap<>();
    // 设备连接信息
    private final Map<String, ConnectionInfo> connectionInfos = new ConcurrentHashMap<>();

    @Autowired
    private MatrixDao matrixDao;
    @PostConstruct
    public void initConnectionsOnStartup() {
        List<Matrix> matrices = matrixDao.selectList(null);
        for (Matrix matrix : matrices) {
            if (matrix.getIp() == null || matrix.getPort() == null) {
//                log.warn("矩阵设备配置错误：{}", matrix.getMatrixName());
                continue;
            }
            String key = generateKey(matrix.getId().toString(), matrix.getIp(), matrix.getPort());
            getDeviceConnection(matrix.getId().toString(), matrix.getIp(), matrix.getPort());
        }
        log.info("服务启动时初始化Modbus连接");
    }
    /**
     * 获取设备连接
     */
    public ModbusMaster getDeviceConnection(String deviceId,String ip,int port) {
        String key = generateKey(deviceId, ip, port);
       return  deviceConnections.computeIfAbsent(key, k -> {
            ModbusMaster master = createMaster(ip, port);
            try{
                master.init();
                connectionInfos.put(key, new ConnectionInfo(deviceId, ip, port, System.currentTimeMillis()));
                log.info("创建Modbus连接成功: {} -> {}:{}", deviceId, ip, port);
            }catch (Exception e){
                log.error("初始化Modbus连接失败: {}:{}", ip, port, e);
                throw new RuntimeException("Modbus连接初始化失败", e);
            }
            return master;
        });
    }

    /**
     * 关闭指定设备的连接
     */
    public boolean closeConnection(String deviceId, String ip, int port) {
        String key = generateKey(deviceId, ip, port);
        return closeConnectionByKey(key);
    }


    /**
     * 根据设备ID关闭连接（适用于只知道设备ID的情况）
     */
    private boolean closeConnectionByKey(String key) {
        try {
            ModbusMaster master = deviceConnections.remove(key);
            ConnectionInfo connectionInfo = connectionInfos.remove(key);

            if (master == null) {
                log.warn("连接不存在: {}", key);
                return false;
            }
            // 关闭连接
            master.destroy();

            if (connectionInfo != null) {
                long duration = System.currentTimeMillis() - connectionInfo.getCreateTime();
                log.info("关闭Modbus连接成功: {} -> {}:{}, 连接时长: {}ms",
                        connectionInfo.getDeviceId(), connectionInfo.getIp(),
                        connectionInfo.getPort(), duration);
            } else {
                log.info("关闭Modbus连接成功: {}", key);
            }

            return true;

        } catch (Exception e) {
            log.error("关闭Modbus连接失败: {}", key, e);
            // 即使关闭失败，也从映射中移除，避免内存泄漏
            deviceConnections.remove(key);
            connectionInfos.remove(key);
            return false;
        }
    }

    /**
     * 关闭所有连接
     */
    public void closeAllConnections() {
        log.info("开始关闭所有Modbus连接，共{}个连接", deviceConnections.size());

        List<String> keys = new ArrayList<>(deviceConnections.keySet());
        int successCount = 0;
        int failCount = 0;

        for (String key : keys) {
            if (closeConnectionByKey(key)) {
                successCount++;
            } else {
                failCount++;
            }
        }

        log.info("关闭所有连接完成: 成功={}, 失败={}", successCount, failCount);
    }

    /**
     * 安全地重新连接设备
     */
    public boolean reconnectDevice(String deviceId, String ip, int port) {
        String key = generateKey(deviceId, ip, port);

        try {
            // 先关闭旧连接
            closeConnectionByKey(key);

            // 创建新连接
            ModbusMaster newMaster = createMaster(ip, port);
            newMaster.init();

            deviceConnections.put(key, newMaster);
            connectionInfos.put(key, new ConnectionInfo(deviceId, ip, port, System.currentTimeMillis()));

            log.info("设备重新连接成功: {} -> {}:{}", deviceId, ip, port);
            return true;

        } catch (Exception e) {
            log.error("设备重新连接失败: {} -> {}:{}", deviceId, ip, port, e);
            return false;
        }
    }
    /**
     * 获取连接状态信息
     */
    public Map<String, ConnectionStatus> getConnectionStatus() {
        Map<String, ConnectionStatus> statusMap = new HashMap<>();

        connectionInfos.forEach((key, connInfo) -> {
            ModbusMaster master = deviceConnections.get(key);
            ConnectionStatus status = new ConnectionStatus();
            status.setDeviceId(connInfo.getDeviceId());
            status.setIp(connInfo.getIp());
            status.setPort(connInfo.getPort());
            status.setConnected(isConnectionActive(master));
            status.setCreateTime(new Date(connInfo.getCreateTime()));
            status.setLastActivity(new Date()); // 可以根据需要记录最后活动时间

            statusMap.put(key, status);
        });

        return statusMap;
    }

    /**
     * 检查连接是否活跃
     */
    private boolean isConnectionActive(ModbusMaster master) {
        if (master == null) {
            return false;
        }
        try {
            return master.isConnected();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 清理无效连接
     */
    public int cleanupInvalidConnections() {
        List<String> invalidKeys = new ArrayList<>();

        deviceConnections.forEach((key, master) -> {
            if (!isConnectionActive(master)) {
                invalidKeys.add(key);
            }
        });

        for (String key : invalidKeys) {
            closeConnectionByKey(key);
        }

        log.info("清理了{}个无效连接", invalidKeys.size());
        return invalidKeys.size();
    }

    /**
     * 根据连接键关闭连接
     */
    private ModbusMaster createMaster(String ip, int port) {
        IpParameters params = new IpParameters();
        params.setHost(ip);
        params.setPort(port);
        ModbusFactory modbusFactory = new ModbusFactory();
        return modbusFactory.createTcpMaster(
                params,false
        );
    }


    /**
     * 生成key
     * @param deviceId
     * @param ip
     * @param port
     * @return
     */
    private String generateKey(String deviceId, String ip, int port) {
        return String.format("%s@%s:%d", deviceId, ip, port);
    }

}
